#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "demo.h"


static cairo_surface_t *surface;

static void clear_surface(cairo_surface_t *surface)
{
    g_assert(surface);

    cairo_t *cr = cairo_create(surface);
    cairo_set_source_rgb(cr, 1, 1, 1);
    cairo_paint(cr);
    cairo_destroy(cr);    
}

static void destroy_cb(GtkWidget *object, gpointer user_data)
{
    if(surface)
        cairo_surface_destroy(surface);
}

static gboolean config_event_cb(GtkWidget* widget
                                , GdkEventConfigure *event
                                , gpointer user_data)
{

    if(surface)
        cairo_surface_destroy(surface);

    surface = gdk_window_create_similar_surface(gtk_widget_get_window(widget)
                                                    , CAIRO_CONTENT_COLOR
                                                    , gtk_widget_get_allocated_width(widget)
                                                    , gtk_widget_get_allocated_height(widget));
    clear_surface(surface);
    
    //this event is handled, no further processing
    return TRUE;
}


static gboolean draw_cb(GtkWidget* widget
                            , cairo_t *cr
                            , gpointer data)
{
    cairo_set_source_surface(cr, surface, 0, 0);
    cairo_paint(cr);

    //propagate the event further
    return FALSE;
}

static void draw_brush(GtkWidget *widget, gdouble x, gdouble y)
{
    cairo_t *cr = cairo_create(surface);
    cairo_rectangle(cr, x-0.5, y-0.5, 1, 1);
    cairo_fill(cr);    
    cairo_destroy(cr);

    gtk_widget_queue_draw(widget);
}

static void do_clear(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
    GtkWidget *widget = user_data;

    clear_surface(surface);
    gtk_widget_queue_draw(widget);
}

static void closed_cb(GtkPopover *popover, gpointer user_data)
{
    g_print("gtkPopover is closed. \n");
}

static void edit_action(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
    g_print ("Action %s activated\n", g_action_get_name(G_ACTION(action)));
}

static GActionEntry actions[] = {
  { "clear", do_clear, NULL, NULL,      NULL },
  { "copy", edit_action, NULL, NULL,      NULL },
  { "cut", edit_action, NULL, NULL,      NULL },
  { "paste", edit_action, NULL, NULL,      NULL },
};

static GActionGroup* get_group(GtkWidget *widget)
{
    GSimpleActionGroup *group;

    group = g_simple_action_group_new();

    g_action_map_add_action_entries(G_ACTION_MAP(group), actions, G_N_ELEMENTS(actions), widget);

    return G_ACTION_GROUP(group);
}


static const gchar *context_menu =
  "<interface>\n"
  "<menu id='context-menu'>\n"
  "  <section>\n"
  "    <item>\n"
  "      <attribute name='action'>actions.clear</attribute>\n"
  "      <attribute name='label'>_Clear</attribute>\n"
  "    </item>\n"
  "  </section>\n"
  "  <section/>\n"
  "  <section>\n"
  "    <item>\n"
  "      <attribute name='label'>Cut</attribute>\n"
  "      <attribute name='action'>actions.cut</attribute>\n"
  "    </item>\n"
  "    <item>\n"
  "      <attribute name='label'>Copy</attribute>\n"
  "      <attribute name='action'>actions.copy</attribute>\n"
  "    </item>\n"
  "    <item>\n"
  "      <attribute name='label'>Paste</attribute>\n"
  "      <attribute name='action'>actions.paste</attribute>\n"
  "    </item>\n"
  "  </section>\n"
  "</menu>\n"
  "</interface>\n";

static GMenuModel* get_model(void)
{
  GError *error = NULL;
  GtkBuilder *builder;
  GMenuModel *menu;

  builder = gtk_builder_new ();
  gtk_builder_add_from_string (builder, context_menu, -1, &error);
  g_assert_no_error (error);

  menu = G_MENU_MODEL(g_object_ref(gtk_builder_get_object(builder, "context-menu")));
  g_object_unref (builder);


  return menu;
}


static void popup_context_menu(GtkWidget *widget, const GdkRectangle *rect)
{
    //载入menu model和action group

    GMenuModel *model;
    GActionGroup *group;

    model = get_model();
    group = get_group(widget);

    //build the popover and popup it.

    GtkWidget *popover;
    popover = gtk_popover_new_from_model(widget, model);
    gtk_popover_set_pointing_to(GTK_POPOVER(popover), rect);                 //设定context-menu pos
    g_signal_connect(popover, "closed", G_CALLBACK(closed_cb), NULL);
    gtk_widget_insert_action_group(popover, "actions", group);
    g_object_unref(group);

    gtk_popover_popup (GTK_POPOVER(popover));
}

static gboolean button_press_event_cb(GtkWidget *widget
                                        , GdkEventButton *event
                                        , gpointer data)
{
    //in case we get no configure-event
    if(surface == NULL)
        return FALSE;

    if(event->button == GDK_BUTTON_PRIMARY)
    {
        draw_brush(widget, event->x, event->y);
    }
    else if (event->button == GDK_BUTTON_SECONDARY)
    {
        GdkRectangle rect;
        rect.x = (gint) event->x;
        rect.y = (gint) event->y;
        rect.height = rect.width = 1;

        popup_context_menu(widget, &rect);
    }

    //no further processing
    return TRUE;
}

static gboolean motion_notify_event_cb(GtkWidget *widget
                                        , GdkEventMotion *event
                                        , gpointer data)
{
    //in case we get no configure-event
    if(surface == NULL)
        return FALSE;

    if(event->state & GDK_BUTTON1_MASK)
        draw_brush(widget, event->x, event->y);

    //stop propagate
    return TRUE;
}




void do_popover(GtkBox *parent)
{
    GtkWidget* frame;
    GtkWidget* vbox;
    GtkWidget *drawing_area;



    frame = gtk_frame_new("popover");
    gtk_container_set_border_width(GTK_CONTAINER(frame), 10);
    gtk_box_pack_start(parent, frame, TRUE, TRUE, 0);

    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
    gtk_container_add(GTK_CONTAINER(frame), vbox);

    drawing_area = gtk_drawing_area_new();
    gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE, TRUE, 5);

    g_signal_connect(drawing_area, "destroy", G_CALLBACK(destroy_cb), NULL);
    g_signal_connect(drawing_area, "configure-event", G_CALLBACK(config_event_cb), NULL);
    g_signal_connect(drawing_area, "draw", G_CALLBACK(draw_cb), NULL);
    g_signal_connect(drawing_area, "button-press-event", G_CALLBACK(button_press_event_cb), NULL);
    g_signal_connect(drawing_area, "motion-notify-event", G_CALLBACK(motion_notify_event_cb), NULL);

    gtk_widget_set_events(drawing_area, gtk_widget_get_events(drawing_area)
                                            | GDK_BUTTON_PRESS_MASK
                                            | GDK_BUTTON_MOTION_MASK);
    gtk_widget_show_all(GTK_WIDGET(parent));    
}
